﻿using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using DesignerHelper.Main;
using SpreadsheetGear;
using SpreadsheetGear.Windows.Forms;
using WorkbookDesigner.Main;

namespace WorkbookDesigner.Addons.DefineName
{
    public partial class DefineNameDialog : Form
    {
        private WorkbookView ActiveView { get; set; }

        private bool InSelectingMode { get; set; }

        private IWorkbook AffectedBook { get; set; }

        private IWorksheet AffectedSheet { get; set; }

        private IWorkbookSet Wbs { get; set; }

        private string DefineName
        {
            get { return textBoxName.Text; }
            set { textBoxName.Text = value; }
        }

        private OperationType WorkType
        {
            get
            {
                // ReSharper disable once ConvertPropertyToExpressionBody
                return comboBoxAffectRange.SelectedIndex == 0 ? OperationType.Workbook : OperationType.Worksheet;
            }
        }

        private string NameRefersTo
        {
            get { return textBoxRefersTo.Text; }
            set { textBoxRefersTo.Text = value; }
        }

        private bool AllowToSelectRange
        {
            get { return buttonSelect.Enabled; }
            set { buttonSelect.Enabled = value; }
        }

        private bool AllowToSelectAffectRange
        {
            get { return comboBoxAffectRange.Enabled; }
            set { comboBoxAffectRange.Enabled = value; }
        }

        #region 初始化函数

        private DefineNameDialog()
        {
            InitializeComponent();
        }

        public DefineNameDialog(IWorkbook bookIn, bool enableRangeSelection = false, bool enableSelectAffectRange = false) : this()
        {
            AllowToSelectAffectRange = enableSelectAffectRange;
            AllowToSelectRange = enableRangeSelection;

            TriggerInit(bookIn);
        }

        public DefineNameDialog(IWorksheet sheetIn, bool enableRangeSelection = false, bool enableSelectAffectRange = false) : this()
        {
            AllowToSelectAffectRange = enableSelectAffectRange;
            AllowToSelectRange = enableRangeSelection;

            AffectedSheet = sheetIn;
            AffectedBook = sheetIn.Workbook;
            TriggerInit(AffectedSheet);
        }

        public DefineNameDialog(WorkbookView wbv) : this()
        {
            AllowToSelectAffectRange = true;
            AllowToSelectRange = true;
            ActiveView = wbv;
            HookEvents();
            TriggerInit(ActiveView);
        }

        public DefineNameDialog(IName nameToEdit, IWorkbook affectedBook) : this()
        {
            AllowToSelectRange = true;
            AllowToSelectAffectRange = false;
            IRange range = nameToEdit.RefersToRange;

            if (range == null) return;
            //IWorksheet worksheet = range.Worksheet;
            IWorkbook workbook = affectedBook;
            InitRangeList(workbook);
            string refersTo = nameToEdit.RefersTo;
            NameRefersTo = refersTo;
            DefineName = nameToEdit.Name;
            Wbs = workbook.WorkbookSet;
            //ActiveView = FormManager.ViewList.Find(x => x.ActiveWorkbook == workbook);
        }

        private void InitRangeList(IWorkbook workbook)
        {
            comboBoxAffectRange.Items.Clear();
            ComboBox.ObjectCollection newlist = new ComboBox.ObjectCollection(comboBoxAffectRange);
            object[] items = new object[workbook.Worksheets.Count + 1];
            items[0] = workbook;
            for (int i = 0; i < workbook.Worksheets.Count; i++)
            {
                items[i + 1] = workbook.Worksheets[i];
            }
            newlist.AddRange(items);
            comboBoxAffectRange.Items.AddRange(items);
            comboBoxAffectRange.SelectedIndex = 0;
        }

        private void InitRangeList(IWorksheet sheet)
        {
            InitRangeList(sheet.Workbook);
            comboBoxAffectRange.SelectedIndex = sheet.Index + 1;
            AllowToSelectAffectRange = false;
        }
        #endregion

        private void TriggerInit(IWorkbook workbook)
        {
            ActiveView = null;
            AffectedBook = workbook;
            Wbs = workbook.WorkbookSet;
            Wbs.DoWork(() =>
            {
                AffectedSheet = workbook.ActiveWorksheet;
                InitRangeList(workbook);
            });
        }

        private void TriggerInit(IWorksheet worksheet)
        {
            ActiveView = null;
            Wbs = worksheet.WorkbookSet;
            Wbs.DoWork(() =>
            {
                InitRangeList(worksheet);
            });
        }
        private void TriggerInit(WorkbookView activeView)
        {
            AffectedSheet = activeView.ActiveWorksheet;
            AffectedBook = AffectedSheet.Workbook;
            Wbs = activeView.ActiveWorkbookSet;
            Wbs.DoWork(() =>
            {
                InitRangeList(AffectedBook);
                RefreshRefersToText(activeView.RangeSelection);
            });
        }

        private void ReceiveRangeThenRefresh(object sender, RangeSelectionChangedEventArgs e)
        {
            if (InSelectingMode)
                RefreshRefersToText(e.RangeSelection);
        }

        private void RefreshRefersToText(IRange range)
        {
            Wbs.DoWork(() =>
            {
                string address = range.GetAddress(true, true, ReferenceStyle.A1, true, null);
                NameRefersTo = "=" + address;
            });
        }

        private INames GetINames()
        {
            OperationType destinationAddedTo = WorkType;
            switch (destinationAddedTo)
            {
                case OperationType.Workbook:
                    return AffectedBook.Names;

                case OperationType.Worksheet:
                    return AffectedSheet.Names;
                default:
                    throw new ArgumentOutOfRangeException();
            }

        }
        #region 唯一窗口
        private static DefineNameDialog DnDialog { get; set; }


        public static void CloseStaticDialog()
        {
            DnDialog?.Close();
        }

        internal class NameEditor : DefineNameDialog
        {
            private IName Edit { get; set; }

            internal NameEditor(IName nameIn, IWorkbook selectedBook) : base(nameIn, selectedBook)
            {
                Text = "修改名称";
                Edit = nameIn;
            }

            private new string Text
            {
                get { return base.Text; }
                set { base.Text = value; }
            }

            private new Size MinimumSize
            {
                get { return base.MinimumSize; }
                set { base.MinimumSize = value; }
            }

            protected override void AddName()
            {
                Wbs.DoWork(() =>
                {
                    Edit.Name = textBoxName.Text;
                    Edit.RefersTo = NameRefersTo;
                });
                Close();
            }
        }


        #endregion

        private void HookEvents()
        {
            if (ActiveView == null)
                return;
            ActiveView.HollowSelection = true;
            ActiveView.RangeSelectionChanged += ReceiveRangeThenRefresh;
        }

        private void UnhookEvents()
        {
            if (ActiveView == null)
                return;
            ActiveView.HollowSelection = false;
            ActiveView.RangeSelectionChanged -= ReceiveRangeThenRefresh;
        }

        protected virtual void AddName()
        {
            Wbs.DoWork(() =>
            {
                try
                {
                    INames names = GetINames();
                    if (Helper.ValidateName(names, DefineName))
                    {
                        names.Add(DefineName, NameRefersTo, ReferenceStyle.A1);
                        Close();
                    }
                }
                catch (ArgumentException)
                {
                    DesignerHelper.Help.MesBox.ErrorMessage("无效的定义名称或公式，请检查！");
                }
            });
        }

        private void Transform4Selecting()
        {
            if (!InSelectingMode)
            {
                //Controls.Remove(panelName);
                //Controls.Remove(panelAffectRange);

                panelButton.Visible = false;

                panelName.Visible = false;
                panelAffectRange.Visible = false;

                InSelectingMode = true;
            }
            else
            {
                //Controls.Add(panelAffectRange);
                //Controls.Add(panelName);

                panelName.Visible = true;
                panelAffectRange.Visible = true;

                panelButton.Visible = true;

                InSelectingMode = false;
            }
        }


        private void buttonSelect_Click(object sender, EventArgs e)
        {
            RefreshRefersToText(ActiveView.RangeSelection);
            Transform4Selecting();
        }

        private void NewDefineNameDialog_FormClosed(object sender, FormClosedEventArgs e)
        {
            UnhookEvents();
            DnDialog = null;
        }

        private void buttonOk_Click(object sender, EventArgs e)
        {
            AddName();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void comboBoxAffectRange_SelectionChangeCommitted(object sender, EventArgs e)
        {
            int i = comboBoxAffectRange.SelectedIndex;
            Wbs.DoWork(() =>
            {
                AffectedSheet = i > 0 ? AffectedBook.Worksheets[i - 1] : AffectedBook.ActiveWorksheet;
            });
        }

        private void DefineNameDialog_FormClosing(object sender, FormClosingEventArgs e)
        {
            //UnhookEvents();
        }
    }
}
